////////////////////////////////////////////////////////////////////////////////////////
//
// JSimpleSim - A machine language simulator based on SimpSim by Anne-Gert Bultena.
//
// Copyright (C) 2008 Gerardo Camorlinga, Ryan Fitzgerald, and RJ Gordon
//
// This file is part of JSimpleSim.
//
// JSimpleSim is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// JSimpleSim is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with JSimpleSim.  If not, see <http://www.gnu.org/licenses/>.
//
////////////////////////////////////////////////////////////////////////////////////////

package jsimplesim.assembler;

import java.util.Hashtable;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;

/**
 * 
 * @author f08maroon
 */
public class AssemblerPassOneTest {

    @Before
    public void setUp() {
    }

    @Test
    public void SymbolDetection() {
        String test = "Test:\n    halt\nNotHere: ";

        Assembler apo = new Assembler(test);
        Hashtable<String, Integer> temp = apo.getSymbolTable();

        assertTrue(temp.containsKey("Test".toLowerCase()));

        assertTrue(temp.containsKey("NotHere".toLowerCase()));

    }

    @Test
    public void MultipleSymbolDetection() {
        String test = "Test:    \nBest: \nCrest:    halt";

        Assembler apo = new Assembler(test);
        Hashtable<String, Integer> temp = apo.getSymbolTable();
        assertTrue(temp.containsKey("Test".toLowerCase()));

        assertTrue(temp.containsKey("Best".toLowerCase()));

        assertTrue(temp.containsKey("Crest".toLowerCase()));
    }

    @Test
    public void loadOpcodeDetection() {
        String test = "Test:    load R1, 0xAA\n    load R2, [0x12]\n    load R3, [R4]\n    halt";

        Assembler apo = new Assembler(test);
        byte[] temp = apo.getInstructions();

        assertEquals(temp[0], 33); // 0x21
        assertEquals(temp[1], -86); // 0xAA

        assertEquals(temp[2], 18); // 0x12
        assertEquals(temp[3], 18); // 0x12

        assertEquals(temp[4], (byte) 208); // 0xD0
        assertEquals(temp[5], 52); // 0x34
    }

    @Test
    public void storeOpcodeDetection() {
        String test = "Test:    store R1, [8]\n    store R2, [R2]\n    halt";

        Assembler apo = new Assembler(test);
        byte[] temp = apo.getInstructions();

        assertEquals(temp[0], 49); // 0x31
        assertEquals(temp[1], 8); // 0x08

        assertEquals(temp[2], (byte) 224); // 0xE0
        assertEquals(temp[3], 34); // 0x08

        assertEquals(temp[4], (byte) 192); // 0xC0 halt
        assertEquals(temp[5], 0); // 0x00
    }

    @Test
    public void moveOpcodeDetection() {
        String test = "Test:    move R1, R3\n    move R2, R4\n    halt";

        Assembler apo = new Assembler(test);
        byte[] temp = apo.getInstructions();

        assertEquals(temp[0], 64); // 0x64
        assertEquals(temp[1], 49); // 0x13

        assertEquals(temp[2], 64); // 0x64
        assertEquals(temp[3], 66); // 0x24

    }

    @Test
    public void addiOpcodeDetection() {
        String test = "Test:    addi R0, R1, R3\n    addi R2, R4, R5\n    halt";

        Assembler apo = new Assembler(test);
        byte[] temp = apo.getInstructions();

        assertEquals(temp[0], 80); // 0x50
        assertEquals(temp[1], 19); // 0x13

        assertEquals(temp[2], 82); // 0x52
        assertEquals(temp[3], 69); // 0x45

    }

    @Test
    public void jmpOpcodeDetection() {
        String test = "Test:    jmpLE R1<=R0, [0xAA]\n    jmpEQ R2=R0, [0x12]\n    jmp [0x12]\n    halt";

        Assembler apo = new Assembler(test);
        byte[] temp = apo.getInstructions();

        //for (int i=0; i<temp.length; i++)
        //	System.out.println("Temp[" + i + "] = " + temp[i]);
        assertEquals(temp[0], (byte) Integer.parseInt("F1", 16));
        assertEquals(temp[1], (byte) Integer.parseInt("AA", 16));
        assertEquals(temp[2], (byte) Integer.parseInt("B2", 16));
        assertEquals(temp[3], 18);
        assertEquals(temp[4], (byte) Integer.parseInt("B0", 16));
        assertEquals(temp[5], 18);

    }

    @Test
    public void rorOpcodeDetection() {
        String test = "Test:    ror R1, 10\n    ror R2, 55\n    ror R5,12\n    halt";

        Assembler apo = new Assembler(test);
        byte[] temp = apo.getInstructions();

        assertEquals(temp[0], (byte) Integer.parseInt("A1", 16));
        assertEquals(temp[1], (byte) 10);
        assertEquals(temp[2], (byte) Integer.parseInt("A2", 16));
        assertEquals(temp[3], (byte) 55);
        assertEquals(temp[4], (byte) Integer.parseInt("A5", 16));
        assertEquals(temp[5], (byte) 12);

    }

    @Test
    public void addfOpcodeDetection() {
        String test = "Test:    addf R0, R1, R3\n    addf R2, R4, R5\n    halt";

        Assembler apo = new Assembler(test);
        byte[] temp = apo.getInstructions();

        assertEquals(temp[0], 96); // 0x60
        assertEquals(temp[1], 19); // 0x13

        assertEquals(temp[2], 98); // 0x62
        assertEquals(temp[3], 69); // 0x45

    }

    @Test
    public void orOpcodeDetection() {
        String test = "Test:    OR R0, R1, R3\n    OR R2, R4, R5\n    halt";

        Assembler apo = new Assembler(test);
        byte[] temp = apo.getInstructions();

        assertEquals(temp[0], (byte) Integer.parseInt("70", 16)); // 0x70
        assertEquals(temp[1], 19); // 0x13

        assertEquals(temp[2], (byte) Integer.parseInt("72", 16)); // 0x72
        assertEquals(temp[3], 69); // 0x45

    }

    @Test
    public void xorOpcodeDetection() {
        String test = "Test:    XOR R0, R1, R3\n    XOR R2, R4, R5\n    halt";

        Assembler apo = new Assembler(test);
        byte[] temp = apo.getInstructions();

        assertEquals(temp[0], (byte) Integer.parseInt("90", 16)); // 0x90
        assertEquals(temp[1], 19); // 0x13

        assertEquals(temp[2], (byte) Integer.parseInt("92", 16)); // 0x92
        assertEquals(temp[3], 69); // 0x45

    }

    @Test
    public void andOpcodeDetection() {
        String test = "Test:    AND R0, R1, R3\n    AND R2, R4, R5\n    halt";

        Assembler apo = new Assembler(test);
        byte[] temp = apo.getInstructions();

        assertEquals(temp[0], (byte) Integer.parseInt("80", 16)); // 0x80
        assertEquals(temp[1], 19); // 0x13

        assertEquals(temp[2], (byte) Integer.parseInt("82", 16)); // 0x82
        assertEquals(temp[3], 69); // 0x45

    }

    @Test
    public void orgOpcodeDetection() {
        String test = "org    50\nTest: addf R1, R2, R3\n    halt";

        Assembler apo = new Assembler(test);
        byte[] temp = apo.getInstructions();

        assertEquals(temp[50], (byte) Integer.parseInt("61", 16));
        assertEquals(temp[51], (byte) Integer.parseInt("23", 16));

        assertEquals(temp[52], (byte) Integer.parseInt("C0", 16));
        assertEquals(temp[53], 0);
    }

    @Test
    public void dbOpcodeDetection() {
        String test = "Test: addf R1, R2, R3\n    org 0xD0\n    db 12, 34, 0x56, 9, \"ab\"\n    halt";

        Assembler apo = new Assembler(test);
        byte[] temp = apo.getInstructions();

        assertEquals(temp[0], (byte) Integer.parseInt("61", 16));
        assertEquals(temp[1], (byte) Integer.parseInt("23", 16));

        assertEquals(temp[208], (byte) Integer.parseInt("12"));
        assertEquals(temp[209], (byte) Integer.parseInt("34"));
        assertEquals(temp[210], (byte) Integer.parseInt("56", 16));
        assertEquals(temp[211], (byte) Integer.parseInt("9"));
        assertEquals(temp[212], (byte) Integer.parseInt("61", 16));
        assertEquals(temp[213], (byte) Integer.parseInt("62", 16));
    }

    //@Test
    //public void 
    @Test
    public void helloWorldTest() {
        String test = "         load    R1,Text     ;the start of the string\n         load    R2,1        ;increase step\n         load    R0,0        ;string-terminator\nNextChar:load    RF,[R1]     ;get character and print it on screen\n         addi    R1,R1,R2    ;increase address\n         jmpEQ   RF=R0,Ready ;when string-terminator, then ready\n         jmp     NextChar    ;next character\nReady:   halt\n\nText:    db      10\n         db      \"Hello world !!\",10\n         db      \"    from the\",10\n         db      \"  Simple Simulator\",10\n         db      0           ;string-terminator\n";

        Assembler apo = new Assembler(test);

        byte[] temp = apo.getInstructions();

        assertEquals(temp[0], (byte) Integer.parseInt("21", 16));
        assertEquals(temp[1], (byte) Integer.parseInt("10", 16));
        assertEquals(temp[2], (byte) Integer.parseInt("22", 16));
        assertEquals(temp[3], (byte) Integer.parseInt("01", 16));
        assertEquals(temp[4], (byte) Integer.parseInt("20", 16));
        assertEquals(temp[5], (byte) Integer.parseInt("00", 16));
        assertEquals(temp[6], (byte) Integer.parseInt("D0", 16));
        assertEquals(temp[7], (byte) Integer.parseInt("F1", 16));
        assertEquals(temp[8], (byte) Integer.parseInt("51", 16));
        assertEquals(temp[9], (byte) Integer.parseInt("12", 16));
        assertEquals(temp[10], (byte) Integer.parseInt("BF", 16));
        assertEquals(temp[11], (byte) Integer.parseInt("0E", 16));
        assertEquals(temp[12], (byte) Integer.parseInt("B0", 16));
        assertEquals(temp[13], (byte) Integer.parseInt("06", 16));
        assertEquals(temp[14], (byte) Integer.parseInt("C0", 16));
        assertEquals(temp[15], (byte) Integer.parseInt("00", 16));
        //FIRST LINE
        assertEquals(temp[16], (byte) Integer.parseInt("0A", 16));
        assertEquals(temp[17], (byte) Integer.parseInt("48", 16));
        assertEquals(temp[18], (byte) Integer.parseInt("65", 16));
        assertEquals(temp[19], (byte) Integer.parseInt("6C", 16));
        assertEquals(temp[20], (byte) Integer.parseInt("6C", 16));
        assertEquals(temp[21], (byte) Integer.parseInt("6F", 16));
        assertEquals(temp[22], (byte) Integer.parseInt("20", 16));
        assertEquals(temp[23], (byte) Integer.parseInt("77", 16));
        assertEquals(temp[24], (byte) Integer.parseInt("6F", 16));
        assertEquals(temp[25], (byte) Integer.parseInt("72", 16));
        assertEquals(temp[26], (byte) Integer.parseInt("6C", 16));
        assertEquals(temp[27], (byte) Integer.parseInt("64", 16));
        assertEquals(temp[28], (byte) Integer.parseInt("20", 16));
        assertEquals(temp[29], (byte) Integer.parseInt("21", 16));
        assertEquals(temp[30], (byte) Integer.parseInt("21", 16));
        assertEquals(temp[31], (byte) Integer.parseInt("0A", 16));
        //SECOND LINE
        assertEquals(temp[32], (byte) Integer.parseInt("20", 16));
        assertEquals(temp[33], (byte) Integer.parseInt("20", 16));
        assertEquals(temp[34], (byte) Integer.parseInt("20", 16));
        assertEquals(temp[35], (byte) Integer.parseInt("20", 16));
        assertEquals(temp[36], (byte) Integer.parseInt("66", 16));
        assertEquals(temp[37], (byte) Integer.parseInt("72", 16));
        assertEquals(temp[38], (byte) Integer.parseInt("6F", 16));
        assertEquals(temp[39], (byte) Integer.parseInt("6D", 16));
        assertEquals(temp[40], (byte) Integer.parseInt("20", 16));
        assertEquals(temp[41], (byte) Integer.parseInt("74", 16));
        assertEquals(temp[42], (byte) Integer.parseInt("68", 16));
        assertEquals(temp[43], (byte) Integer.parseInt("65", 16));
        assertEquals(temp[44], (byte) Integer.parseInt("0A", 16));
        assertEquals(temp[45], (byte) Integer.parseInt("20", 16));
        assertEquals(temp[46], (byte) Integer.parseInt("20", 16));
        assertEquals(temp[47], (byte) Integer.parseInt("53", 16));
        //THIRD LINE
        assertEquals(temp[48], (byte) Integer.parseInt("69", 16));
        assertEquals(temp[49], (byte) Integer.parseInt("6D", 16));
        assertEquals(temp[50], (byte) Integer.parseInt("70", 16));
        assertEquals(temp[51], (byte) Integer.parseInt("6C", 16));
        assertEquals(temp[52], (byte) Integer.parseInt("65", 16));
        assertEquals(temp[53], (byte) Integer.parseInt("20", 16));
        assertEquals(temp[54], (byte) Integer.parseInt("53", 16));
        assertEquals(temp[55], (byte) Integer.parseInt("69", 16));
        assertEquals(temp[56], (byte) Integer.parseInt("6D", 16));
        assertEquals(temp[57], (byte) Integer.parseInt("75", 16));
        assertEquals(temp[58], (byte) Integer.parseInt("6C", 16));
        assertEquals(temp[59], (byte) Integer.parseInt("61", 16));
        assertEquals(temp[60], (byte) Integer.parseInt("74", 16));
        assertEquals(temp[61], (byte) Integer.parseInt("6F", 16));
        assertEquals(temp[62], (byte) Integer.parseInt("72", 16));
        assertEquals(temp[63], (byte) Integer.parseInt("0A", 16));
        assertEquals(temp[64], 0);
    }
}